package org.wwy.sql;


import java.io.*;
import java.util.*;

import org.apache.commons.io.IOUtils;

public class SqlFileHandler {


    private File resultBaseFolder;

    public void merge(String sqlFolderPath, String sqlResultName) throws IOException{
        merge(sqlFolderPath,sqlResultName,true);
    }

    public void mergeUpdate(String sqlFolderPath, String sqlResultName,String currentVersion,String targetVersion) throws IOException {
        if(currentVersion == null){
            throw new RuntimeException("当前版本不能问空!");
        }
        if(targetVersion == null){
            throw new RuntimeException("目标版本不能为空!");
        }
        File sqlFolder = new File(sqlFolderPath);
        String[] versionFiles = sqlFolder.list((dir, name) -> name.toLowerCase().startsWith("v"));
        if(versionFiles != null){
            for (String versionFile : versionFiles) {
                String version = versionFile.substring(1);
                String[] versionNums = version.split("\\.");
                if(versionNums.length<3){
                    throw new RuntimeException(versionFile+"版本号必须是三位!");
                }
            }
            List<String> versionList = Arrays.asList(versionFiles);
            Collections.sort(versionList, (o1, o2) -> {
                String[] o1VersionNums = o1.substring(1).split("\\.");
                String[] o2VersionNums = o2.substring(1).split("\\.");
                for (int i=0;i<o1VersionNums.length;i++) {
                    Integer v1 = Integer.valueOf(o1VersionNums[i]);
                    Integer v2 = Integer.valueOf(o2VersionNums[i]);
                    if(v1<v2){
                        return -1;
                    }else if(v1==v2){
                        continue;
                    }else{
                        return 1;
                    }
                }
                return 0;
            });
            int start = versionList.indexOf(currentVersion);
            if(start < 0){
                throw new RuntimeException("文件夹"+sqlFolderPath+"未发现当前版本!");
            }
            int end = versionList.indexOf(targetVersion);
            if(end < 0){
                throw new RuntimeException("文件夹"+sqlFolderPath+"未发现目标版本!");
            }
            List<String> versionResult = new ArrayList<>();
            for(int i=start;i<=end;i++){
                versionResult.add(versionList.get(i));
            }
            //排序后的版本文件
            Map<Integer, File> nums = new LinkedHashMap<>();
            for (String version : versionResult) {
                resolveStdFiles(sqlFolderPath+"/"+version+"/update",false,nums);
            }
            writerFile(sqlResultName, false, nums,sqlFolderPath);
        }
    }

    public void merge(String sqlFolderPath, String sqlResultName,boolean hasNum) throws IOException {
        Map<Integer, File> nums = new TreeMap<>();
        resolveStdFiles(sqlFolderPath, hasNum, nums);
        writerFile(sqlResultName, hasNum, nums,sqlFolderPath);
        }

    /**
     * 标准
     * @param sqlFolderPath
     * @param hasNum
     * @param nums
     */
    private void resolveStdFiles(String sqlFolderPath, boolean hasNum, Map<Integer, File> nums) {
        File sqlFolder = new File(sqlFolderPath);
        String[] sqlFiles = sqlFolder.list((dir, name) -> name.endsWith(".sql"));
        int origSize = nums.size();
        if (sqlFiles != null) {

            int fileCount = 0;
            for (int i=0;i<sqlFiles.length;i++) {
                String sqlFile = sqlFiles[i];
                if(hasNum){
                    String[] split = sqlFile.split("\\.");
                    if (split.length < 3) {
                        throw new RuntimeException("文件[" + sqlFolder.getPath() + "/" + sqlFile + "]不符合规范!");
                    }
                    Integer num;
                    try {
                        num = Integer.valueOf(split[0]);
                    } catch (Exception e) {
                        throw new RuntimeException("文件[" + sqlFile + "]第一位必须是数字!", e);
                    }

                    if (nums.containsKey(num)) {
                        throw new RuntimeException("文件[" + sqlFile + "]存在重复序号!");
                    }
                    nums.put(num, new File(sqlFolder.getPath() + "/" + sqlFile));
                    fileCount++;
                }else{
                    if(fileCount>0) {
                        throw new RuntimeException(sqlFolderPath + "文件夹,存在多个sql文件,并且未标记序号!");
                    }
                    nums.put(origSize+i+1, new File(sqlFolder.getPath() + "/" + sqlFile));
                    fileCount++;
                }
            }
        }
    }

    public void mergeBData(String sqlFolderBasePath, String sqlResultName,String level) throws IOException {
        Map<Integer, File> fileMap = new TreeMap<>();
        resolveFiles(sqlFolderBasePath+"/ddl/"+level, fileMap);
        resolveFiles(sqlFolderBasePath+"/dml/"+level, fileMap);
        writerFile(sqlResultName, false, fileMap,null);
    }

    public void mergeBDataOracle(String sqlFolderPath, String sqlResultName) throws IOException {
        Map<Integer, File> nums = new TreeMap<>();
        resolveFiles(sqlFolderPath, nums);
        writerFile(sqlResultName, false, nums,null);
    }

    private void resolveFiles(String sqlFolderPath, Map<Integer, File> nums) {
        File sqlFolder = new File(sqlFolderPath);
        String[] sqlFiles = sqlFolder.list((dir, name) -> name.endsWith(".sql"));
        int origSize = nums.size();
        if (sqlFiles != null) {
            for (int i=0;i<sqlFiles.length;i++) {
                String sqlFile = sqlFiles[i];
                    nums.put(origSize+i+1, new File(sqlFolder.getPath() + "/" + sqlFile));
            }
        }
    }

    private void writerFile(String sqlResultName, boolean hasNum, Map<Integer, File> fileMaps,
                            String sqlFolderPath) throws IOException {
        FileWriter fileWriter = null;
        try {
            fileWriter = new FileWriter(resultBaseFolder.getPath() + "/" + sqlResultName + ".sql", false);
            int index = 1;
            for (File sqlFile : fileMaps.values()) {
                FileInputStream fileInputStream = new FileInputStream(sqlFile);
                String data = IOUtils.toString(fileInputStream, "utf8");
                fileWriter.write("-----");
                if(!hasNum){
                    fileWriter.write(String.valueOf(index));
                    fileWriter.write(".");
                }
                if(sqlFolderPath == null){
                    fileWriter.write(sqlFile.getName() + "-------\n");
                }else {
                    fileWriter.write(sqlFile.getAbsolutePath().substring(sqlFolderPath.length()+1).replaceAll("\\\\","/") + "-------\n");

                }
                fileWriter.write(data + "\n");
                index++;
            }

        } catch (Exception e) {
            throw new RuntimeException("文件写入失败!", e);
        }finally {
            if(fileWriter != null){
                fileWriter.close();
            }
        }
    }


    public SqlFileHandler(File resultBaseFolder) {
            if (resultBaseFolder == null) {
                throw new RuntimeException("sql结果文件夹不能为空!");
            }
            this.resultBaseFolder = resultBaseFolder;
            if (!resultBaseFolder.exists()) {
                resultBaseFolder.mkdir();
            }
        }
    }
